package org.coco.core;

import lombok.Getter;
import org.coco.core.annotation.Component;
import org.coco.core.annotation.Controller;
import org.coco.core.annotation.Repository;
import org.coco.core.annotation.Service;
import org.coco.inject.annotation.Autowired;
import org.coco.mvc.annotation.Order;
import org.coco.mvc.interceptor.HandlerInterceptor;
import org.coco.util.ClassUtil;
import org.coco.util.ValidationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


public class BeanContainer {

    public static Logger log = LoggerFactory.getLogger(BeanContainer.class);
    //定义Bean实例的载体,存放所有被配置标记的目标对象的Map
    @Getter
    private final Map<Class<?>, Object> map = new ConcurrentHashMap<>();
    //定义用来存储实现了InterceptorHandle接口的对象
    @Getter
    private final Map<Integer,Class<?>> interceptorMap = new ConcurrentHashMap<>();

    @Getter
    private final List<Class<?>> interceptorList = new ArrayList<>();

    /**
     * 判断容器是否已经被加载过,默认是没有
     */
    private boolean loaded = false;

    //加载Bean的注解列表
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION =
            Arrays.asList(Component.class, Controller.class, Service.class, Repository.class);


    private BeanContainer(){}

    private enum ContainerHolder{
        HOLDER;
        private BeanContainer instance;

        ContainerHolder() {
            instance = new BeanContainer();
        }
    }

    /**
     * 获取Bean容器的实例，因为容器只能有一个，所以这里采用单例
     *
     * @return
     */
    public static BeanContainer getInstance() {
        return ContainerHolder.HOLDER.instance;
    }

    /**
     * 容器是否已经被加载过
     *
     * @return 是否已经被加载
     */
    public boolean isload() {
        return loaded;
    }


    /**
     * 扫描加载所有的Bean
     *
     * @Param basePackage:包名
     */
    public synchronized void loadBeans(String[] basePackages) {
        //加载Bean是个很耗时的操作，Bean应该只能被加载一次，所以下一次进来就直接返回，不需要再次进行加载
        if(isload()) {
            log.warn("BeanContain has bean loaded");
            return;
        }
        for(int i = 0; i < basePackages.length; i ++) {
            Set<Class<?>> classSet = ClassUtil.extractPackageClass(basePackages[i]);
            if(ValidationUtil.isEmpty(classSet)) {
                log.warn("extract nothing from packagename:" + basePackages[i]);
                return;
            }
            for(Class<?> clazz : classSet) {
                for (Class<? extends Annotation> annotation : BEAN_ANNOTATION) {
                    //如果类上面标记了定义的注解,或者实现了BeanDefinitionRegistryPostProcessor接口
                    Class<?>[] interfaces = clazz.getInterfaces();
                    boolean isHaveBeanDefinitionRegistryPostProcessorInterface = false;
                    for (Class classInterface : interfaces) {
                        try {
                            if ("org.coco.core.postprocessor.BeanDefinitionRegistryPostProcessor".equals(classInterface.getName())) {
                                isHaveBeanDefinitionRegistryPostProcessorInterface = true;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if (clazz.isAnnotationPresent(annotation) || isHaveBeanDefinitionRegistryPostProcessorInterface) {
                        //将类本身作为键，目标类的实例作为值，存入容器中，也就是该类的map中
                        map.put(clazz,ClassUtil.newInstance(clazz, true));
                    }
                }
            }
        }
        //对拦截器进行排序处理
        filterHaveHandleInterceptorClass(map);
        loaded = true;
    }


    private List<Class<?>> filterHaveHandleInterceptorClass(Map<Class<?>, Object> map) {
        if(map.isEmpty()) {
            return null;
        }
        for(Class<?> clazz : map.keySet()) {
            //如果该类实现了HandlerInterceptor接口，那么就把该类放入一个List的集合中去
            if(HandlerInterceptor.class.isAssignableFrom(clazz)) {
                //判断该类上是否有@Order注解，因为我们要对拦截器进行排序
                if(!clazz.isAnnotationPresent(Order.class)) {
                    log.warn("{} 必须有Order注解",clazz.getName());
                    throw new RuntimeException(clazz.getName() + " not have annotation Order");
                }
                //获取该类上的@Order注解的value的值，好为后面执行的顺序进行排序
                Order order = clazz.getAnnotation(Order.class);
                int orderValue = order.value();
                if(interceptorMap.containsKey(orderValue) || orderValue < 0) {
                    //这里规定@Order的值不能有相同的或者该值不能小于0
                    log.warn("{} 类 Order注解的值: {} 有重复的",clazz.getName(),orderValue);
                    throw new RuntimeException(clazz.getName() + "类的Order注解的值：" + orderValue + "有重复的");
                }
                interceptorMap.put(orderValue,clazz);
            }
        }
        //如果有类实现了HandlerInterceptor，那么我们就要对它进行排序了
        List<Integer> integerList = new ArrayList<>();
        if(!interceptorMap.isEmpty()) {
            for(Integer key : interceptorMap.keySet()) {
                integerList.add(key);
            }
            //对key进行排序，从小到大
            integerList.stream().sorted((a,b)->a.compareTo(b)).collect(Collectors.toList()).forEach(u->{
                interceptorList.add(interceptorMap.get(u));
            });
        }
        return interceptorList;
    }

    /**
     *
     * @return map中实例的数量
     */
    public int getSize() {
        return map.size();
    }

    /**
     * 添加一个class对象及其bean的实例
     *
     * @param clazz  class对象
     * @param bean   bean的实例
     * @return
     */
    public Object addBean(Class<?> clazz,Object bean) {
        return map.put(clazz,bean);
    }

    /**
     * 移除一个IOC容器管理的对象
     *
     * @param clazz  class对象
     * @return 删除bean的实例，没有就返回null
     */
    public Object removeBean(Class<?> clazz) {
        return map.remove(clazz);
    }

    /**
     * 根据class对象获取bean的实例
     *
     * @param clazz
     * @return
     */
    public Object getBean(Class<?> clazz) {
        return map.get(clazz);
    }

    /**
     * 获取容器管理的所有class对象集合
     *
     * @return
     */
    public Set<Class<?>> getClasses() {
        return map.keySet();
    }

    /**
     * 获取所有Bean的集合
     *
     * @return
     */
    public Set<Object> getBeans() {
        return new HashSet<>(map.values());
    }

    /**
     * 根据注解筛选出Bean的Class集合
     *
     * @param annotation 注解
     * @return Class集合
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
        //1.获取beanMap的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        //2.通过注解筛选被注解标记的class对象，并添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz : keySet){
            //类是否有相关的注解标记
            if(clazz.isAnnotationPresent(annotation)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0? classSet: null;
    }
    /**
     * 通过接口或者父类获取实现类或者子类的Class集合，不包括其本身
     *
     * @param interfaceOrClass 接口Class或者父类Class
     * @return Class集合
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
        //1.获取beanMap的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        //2.判断keySet里的元素是否是传入的接口或者类的子类，如果是，就将其添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz : keySet){
            //判断keySet里的元素是否是传入的接口或者类的子类
            if(interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0? classSet: null;
    }
}
